今天要再往下介紹components,elements是由components組合產生的,而components可以有自己的狀態,依照狀態來render HTML。
我們可以把component視為class,因為它可以用javascript的function來表達,也可以用ES6 class的方式建立。而component有兩種形式:
const ele = <div />
const ele = <MyComponent wording="Hello" />
React的components透過繼承React.Component來建立,使用ES6 class定義的方式如下:
class Profile extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
另外,也有提供一個進階的React.PureComponent可以繼承,基本上它和React.Component是一樣的,唯一的差別在於會加上 shouldComponentUpdate 的function,這個function是用來避免component在不必要的狀態下被update,後續應該有機會會再說明清楚,或是可以看官網API的說明。
class Profile extends React.PureComponent {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
上面已經學會如何定義components,加上前一天提到的ReactDOM.render(),這邊用一個完整範例,把component組成一個element,再用React.render渲染出來。
// component
class Profile extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
// element
const ele = <Profile name="Allen" />;
// render to <div id="main"></div>
ReactDOM.render(
ele,
document.getElementById('main')
);
Props是由父元件傳入component的參數,這是在React裡面一個很重要的單向資料流觀念,所有的資訊都是由上層往下傳遞,所以絕對不要在component裡面直接改變props,「Props must be pure」,而React也提供設定props檢查型態與設定預設值的方法。
Profile.propTypes = {
name: React.PropTypes.string.isRequired,
age: React.PropTypes.number.isRequired,
receiveMsg: React.PropTypes.bool
};
Profile.defaultProps = {
receiveMsg: false
}
上面已經對components有完整的了解,這邊要再提到怎麼去拆解與組合components,這是React裡面另一個重要的部分。
以FB的留言版回覆為例,假設Layout架構如下:
├── Comment 留言第一篇
│ ├── Comment 留言第一篇的回覆第一篇
│ └── Comment 留言第一篇的回覆第二篇
└── Comment 留言第二篇
那Comment就會是一個基本component,裡面可能還會包含Avatar、CommentContext、ControlBtn等其他component,例如:
class Comment extends React.Component {
render() {
return (
<div>
<Avatar
img={this.props.img}
name={this.props.name}
/>
<CommentContext comment={this.props.comment} />
<ControlBtn />
</div>
);
}
}
Comment.propTypes = {
img: React.PropTypes.string,
name: React.PropTypes.string.isRequired,
comment: React.PropTypes.string.isRequired
};
Comment.defaultProps = {
img: 'default.png'
}
而整個留言板可以重複使用Comment這個元件
const board = (
<div>
<div className="level1">
<Comment
img="./images/photo1.jpg"
name="Allen"
comment="I think this is good!"
/>
<div className="level2">
<Comment
img="./images/photo3.jpg"
name="Jacky"
comment="Amazing!"
/>
<Comment
img="./images/photo4.jpg"
name="Allen"
comment="Wonderful!"
/>
</div>
</div>
<div className="level1">
<Comment
img="./images/photo2.jpg"
name="John"
comment="Good~"
/>
</div>
</div>
);
Comment可以被重複使用(reusable),用div區隔出來第一層與第二層,而裡面的Avatar、CommentContext、ControlBtn也都可以共用,用複合拼裝的方式reuse元件,而每一個Comment component又是獨立運作的,可以render自己的內容,各自擁有不同的props data。
通常我們可以看著Layout來思考元件該怎麼切割,哪些元件可以依照功能被切出來,哪些元件可以重複共用,多切幾次就會越來越知道怎麼拆分元件。我覺得切元件的方式有點看個人習慣,大致的原則就是依照功能與思考重複使用的可能性,有時候切太細會覺得沒必要,有時候切乾淨會比較好reuse。